package squirrel

import scala.util.{Success, Try}

/**
  * SqlWhere
  */
sealed trait SqlWhere {
  def toSQL: Try[ParameterizedSQL]
}

case object SqlWhereEmpty extends SqlWhere {
  override def toSQL: Try[ParameterizedSQL] =
    Success(ParameterizedSQL("", Seq()))
}

/**
  * SqlWhereRaw
  * @param where String raw where string
  */
case class SqlWhereRaw(where: String) extends SqlWhere {
  override def toSQL: Try[ParameterizedSQL] =
    Success(ParameterizedSQL(where, Seq()))
}
case class SqlWhereAnd(conds: Seq[SqlWhere]) extends SqlWhere {
  override def toSQL: Try[ParameterizedSQL] = {
    val ps = conds.map(_.toSQL)
    ps find (_.isFailure) match {
      case Some(p) => p
      case None =>
        val allPs = ps.map(_.get)
        val sqls  = allPs.map(v => s"(${v.sql})")
        Success(ParameterizedSQL(sqls.mkString(" AND "), allPs.flatMap(_.args)))
    }
  }
}

case class SqlWhereOr(conds: Seq[SqlWhere]) extends SqlWhere {
  override def toSQL: Try[ParameterizedSQL] = {
    val ps = conds.map(_.toSQL)
    ps find (_.isFailure) match {
      case Some(p) => p
      case None =>
        val allPs = ps.map(_.get)
        val sqls  = allPs.map(v => s"(${v.sql})")
        Success(ParameterizedSQL(sqls.mkString(" OR "), allPs.flatMap(_.args)))
    }
  }
}

case class SqlWhereNot(conds: Seq[SqlWhere]) extends SqlWhere {
  override def toSQL: Try[ParameterizedSQL] = {
    val ands = SqlWhereAnd(conds)
    ands.toSQL.map(v => ParameterizedSQL(s"NOT (${v.sql})", v.args))
  }
}

case class SqlWhereEq(field: String, value: SqlValue) extends SqlWhere {
  override def toSQL: Try[ParameterizedSQL] =
    Success(ParameterizedSQL(s"$field = ?", Seq(value)))
}

case class SqlWhereNotEq(field: String, value: SqlValue) extends SqlWhere {
  override def toSQL: Try[ParameterizedSQL] =
    Success(ParameterizedSQL(s"$field <> ?", Seq(value)))
}

case class SqlWhereGt(field: String, value: SqlValue) extends SqlWhere {
  override def toSQL: Try[ParameterizedSQL] =
    Success(ParameterizedSQL(s"$field > ?", Seq(value)))
}

case class SqlWhereGte(field: String, value: SqlValue) extends SqlWhere {
  override def toSQL: Try[ParameterizedSQL] =
    Success(ParameterizedSQL(s"$field >= ?", Seq(value)))
}

case class SqlWhereLt(field: String, value: SqlValue) extends SqlWhere {
  override def toSQL: Try[ParameterizedSQL] =
    Success(ParameterizedSQL(s"$field < ?", Seq(value)))
}

case class SqlWhereLte(field: String, value: SqlValue) extends SqlWhere {
  override def toSQL: Try[ParameterizedSQL] =
    Success(ParameterizedSQL(s"$field <= ?", Seq(value)))
}

case class SqlWhereLike(field: String, value: SqlValue) extends SqlWhere {
  override def toSQL: Try[ParameterizedSQL] =
    Success(ParameterizedSQL(s"$field LIKE ?", Seq(value)))
}

case class SqlWhereNotLike(field: String, value: SqlValue) extends SqlWhere {
  override def toSQL: Try[ParameterizedSQL] =
    Success(ParameterizedSQL(s"$field notLIKE ?", Seq(value)))
}

case class SqlWhereIn(field: String, value: Set[SqlValue]) extends SqlWhere {
  override def toSQL: Try[ParameterizedSQL] = {
    val values = value.toSeq
    Try(ParameterizedSQL(s"""$field IN (${values.map(_ => "?").mkString(",")})""", values))
  }
}
